home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 July: Mac OS SDK / Dev.CD Jul 97 SDK2.toast / Development Kits (Disc 2) / QuickTake Digital Camera / MyQuickTakeApp 1.0.2 ƒ / Sources / Preferences (develop 18) / StdPrefsLib.c next >
Encoding:
Text File  |  1994-11-25  |  32.8 KB  |  1,319 lines  |  [TEXT/KAHL]

  1. /*
  2.     File:        StdPrefsLib.c
  3.  
  4.     Contains:    Standard preferences library routines.
  5.  
  6.                 Refer to develop Issue 18, "The Right Way to Implement 
  7.                 Preferences Files", for additional details on this code.
  8.                 
  9.     Written by:    Gary Woodcock
  10.  
  11.     Copyright:    © 1993-94 by Apple Computer, Inc.
  12.  
  13.     Change History (most recent first):
  14.     
  15.                   3/3/94    Version 1.0.
  16.     
  17.     Notes:         This code uses Apple's Universal Interfaces for C.
  18.     
  19.                 Send bug reports to Gary Woodcock at AOL: gwoodcock
  20.                 or Internet: gwoodcock@aol.com.
  21. */
  22.  
  23. //-----------------------------------------------------------------------
  24. // Includes
  25.  
  26. #include "CompileFlags.h"
  27.  
  28. #include "StdPrefsLib.h"
  29. #include "StdPrefsLibPrivate.h"
  30. #include "DebugUtils.h"
  31. #include "FSpCompat.h"
  32. #include "MoreFilesExtras.h"
  33.  
  34. //-----------------------------------------------------------------------
  35. // Private constants
  36.  
  37. enum
  38. {
  39.     kApplicationMissingMessageStrID = -16397
  40. };
  41.  
  42. //-----------------------------------------------------------------------
  43. // Private prototypes
  44.  
  45. static OSErr
  46. GetPrefsDirVRefNumAndDirID (ConstStr31Param folderName, 
  47.     Boolean createFolder, short *vRefNum, long *dirID);
  48.     
  49. static OSErr
  50. GetPreferencesFileFSSpec (OSType creator, OSType fileType,
  51.     FSSpec *file);
  52.  
  53. static Boolean
  54. DirIDInPrefsDir (short vRefNum, long dirID, long prefsDirID);
  55.     
  56. static short
  57. FindVRefNum (short fRefNum);
  58.  
  59. static unsigned long
  60. GetVolFreeSpace (short vRefNum);
  61.  
  62. static unsigned long
  63. GetVAllocationBlockSize (short vRefNum);
  64.  
  65. static OSErr
  66. GetDirPathName (short vRefNum, long dirID, Str255 pathName);
  67.  
  68. static OSErr
  69. CopyString (ConstStr255Param theSourceStr, Str255 theDestStr);
  70.  
  71. static OSErr
  72. CatenateStrings (ConstStr255Param theFirstStr, 
  73.     ConstStr255Param theSecondStr, Str255 theCatenatedStr);
  74.  
  75. static OSErr
  76. CopyResource (ResType theType, short theID, FSSpec *fileToCopyTo);
  77.  
  78. //-----------------------------------------------------------------------
  79.  
  80. pascal OSErr
  81. NewPreferencesFile (OSType creator, OSType fileType,
  82.     ConstStr31Param fileName, ConstStr31Param folderName, 
  83.     ConstStr31Param ownerName)
  84. {
  85.     OSErr    result = noErr;
  86.     
  87.     // Make sure parameters are valid
  88.     if (fileName != nil)
  89.     {
  90.         long    dirID;
  91.         short    vRefNum;
  92.         
  93.         // Get the vRefNum and dirID for the folder to put the preferences file in
  94.         result = GetPrefsDirVRefNumAndDirID (folderName, true, &vRefNum, &dirID);
  95.         if (result == noErr)
  96.         {
  97.             short    savedResFile = CurResFile();
  98.  
  99.             // Create the file
  100.             HCreateResFile (vRefNum, dirID, fileName);
  101.             result = ResError();
  102.             if (result == noErr)
  103.             {
  104.                 FInfo    info;
  105.                 
  106.                 // Set the file type and creator, and lock the name
  107.                 result = HGetFInfo (vRefNum, dirID, fileName, &info);
  108.                 if (result == noErr)
  109.                 {
  110.                     info.fdType = fileType;
  111.                     info.fdCreator = creator;
  112.                     info.fdFlags |= kNameLocked;
  113.                     result = HSetFInfo (vRefNum, dirID, fileName, &info);
  114.                     if (result == noErr)
  115.                     {
  116.                         // Should we add an application-missing message string?
  117.                         if (ownerName != nil)
  118.                         {
  119.                             Str255    preamble;
  120.                             Str255    postamble;
  121.                                 
  122.                             // Build the application-missing message string
  123.                             GetIndString (preamble, kStdPrefsLibStrsID, kPreambleStrID);
  124.                             GetIndString (postamble, kStdPrefsLibStrsID, kPostambleStrID);
  125.                                         
  126.                             if ((preamble != nil) && (postamble != nil))
  127.                             {
  128.                                 result = CatenateStrings (preamble, *((Str255 *)ownerName), preamble);
  129.                                 if (result == noErr)
  130.                                 {
  131.                                     result = CatenateStrings (preamble, postamble, preamble);
  132.                                     if (result == noErr)
  133.                                     {
  134.                                         short    fRefNum;
  135.                                         
  136.                                         // Open the new file
  137.                                         result = OpenPreferencesFile (creator, fileType, &fRefNum);
  138.                                         if (result == noErr)
  139.                                         {
  140.                                             Handle    messageHdl;
  141.                                             
  142.                                             // Add the application-missing message string
  143.                                             PtrToHand ((Ptr)&preamble, &messageHdl, preamble[0] + 1);
  144.                                             if ((result = MemError()) == noErr)
  145.                                             {
  146.                                                 short    resID = kApplicationMissingMessageStrID;
  147.                                                 
  148.                                                 result = WritePreference (fRefNum, 'STR ', &resID, messageHdl);
  149.                                                 DisposeHandle (messageHdl);
  150.                                                 result = MemError();
  151.                                                 FailMessage (result != noErr, NewPreferencesFile: DisposeHandle failed.);
  152.                                             }
  153.                                             else
  154.                                             {
  155.                                                 DebugMessage (NewPreferencesFile: PtrToHand failed.);
  156.                                             }
  157.                                             
  158.                                             // Close up shop
  159.                                             result = ClosePreferencesFile (fRefNum);
  160.                                         }
  161.                                     }
  162.                                 }
  163.                             }
  164.                             else    // GetIndString failed
  165.                             {
  166.                                 result = -1L;
  167.                                 DebugMessage (NewPreferencesFile: GetIndString failed.);
  168.                             }
  169.                         }
  170.                     }
  171.                     else    // HSetFInfo failed
  172.                     {
  173.                         DebugMessage (NewPreferencesFile: HSetFInfo failed.);
  174.                     }
  175.                 }
  176.                 else    // HGetFInfo failed
  177.                 {
  178.                     DebugMessage (NewPreferencesFile: HGetFInfo failed.);
  179.                 }
  180.             }
  181.             else    // HCreateResFile failed
  182.             {
  183.                 DebugMessage (NewPreferencesFile: HCreateResFile failed.);
  184.             }
  185.             
  186.             // Restore the resource file
  187.             UseResFile (savedResFile);
  188.             result = ResError();
  189.             FailMessage (result != noErr, NewPreferencesFile: UseResFile failed.);
  190.         }
  191.     }
  192.     else    // Bad parameter
  193.     {
  194.         result = paramErr;
  195.         DebugMessage (NewPreferencesFile: Bad parameter);
  196.     }
  197.     return (result);
  198. }
  199.  
  200. //-----------------------------------------------------------------------
  201.  
  202. pascal OSErr
  203. OpenPreferencesFile (OSType creator, OSType fileType, short *fRefNum)
  204. {
  205.     OSErr    result = noErr;
  206.     
  207.     // Make sure parameters are valid
  208.     if (fRefNum != nil)
  209.     {
  210.         FSSpec    prefsFSSpec;
  211.         short    savedResFile = CurResFile();
  212.         
  213.         // Get the FSSpec for the preferences file
  214.         result = GetPreferencesFileFSSpec (creator, fileType, &prefsFSSpec);
  215.         if (result == noErr)
  216.         {
  217.             // Open it up
  218.             
  219.             short    theFRefNum = FSpOpenResFileCompat (&prefsFSSpec, fsRdWrPerm);
  220.             
  221.             result = ResError();
  222.             if (result == noErr)
  223.             {    
  224.                 *fRefNum = theFRefNum;
  225.                 
  226.                 // Restore the resource file
  227.                 UseResFile (savedResFile);
  228.                 result = ResError();
  229.                 FailMessage (result != noErr, OpenPreferencesFile: UseResFile failed.);
  230.             }
  231.             else    // FSpOpenResFileCompat failed
  232.             {
  233.                 DebugMessage (OpenPreferencesFile: FSpOpenResFileCompat failed.);
  234.             }
  235.         }
  236.     }
  237.     else    // Bad parameter
  238.     {
  239.         result = paramErr;
  240.         DebugMessage (OpenPreferencesFile: Bad parameter.);
  241.     }
  242.     return (result);
  243. }
  244.  
  245. //-----------------------------------------------------------------------
  246.  
  247. pascal OSErr
  248. ClosePreferencesFile (short fRefNum)
  249. {
  250.     OSErr    result = noErr;
  251.     
  252.     // Make sure parameters are valid
  253.     if (fRefNum != -1)
  254.     {
  255.         // Close it
  256.         CloseResFile (fRefNum);
  257.         result = ResError();
  258.         FailMessage (result != noErr, ClosePreferencesFile: CloseResFile failed.);
  259.     }
  260.     else    // Bad parameter
  261.     {
  262.         result = paramErr;
  263.         DebugMessage (ClosePreferencesFile: Bad parameter.);
  264.     }
  265.     return (result);
  266. }
  267.  
  268. //-----------------------------------------------------------------------
  269.  
  270. pascal OSErr
  271. DeletePreferencesFile (OSType creator, OSType fileType)
  272. {
  273.     FSSpec    prefsFSSpec;
  274.     OSErr    result;
  275.     
  276.     // Get the preferences file FSSpec
  277.     result = GetPreferencesFileFSSpec (creator, fileType, &prefsFSSpec);
  278.     if (result == noErr)
  279.     {
  280.         // Delete it
  281.         result = FSpDeleteCompat (&prefsFSSpec);
  282.         FailMessage (result != noErr, DeletePreferencesFile: FSpDeleteCompat failed.);
  283.     }
  284.     return (result);
  285. }
  286.  
  287. //-----------------------------------------------------------------------
  288.  
  289. pascal OSErr
  290. DeletePreferencesFolder (ConstStr31Param folderName)
  291. {
  292.     OSErr    result = noErr;
  293.     
  294.     // Make sure the parameters are valid
  295.     if (folderName != nil)
  296.     {
  297.         long    dirID;
  298.         short    vRefNum;
  299.         
  300.         // Get the vRefNum and dirID of the preferences folder
  301.         result = GetPrefsDirVRefNumAndDirID (folderName, false, &vRefNum, &dirID);
  302.         if (result == noErr)
  303.         {
  304.             Str255    pathName;
  305.             
  306.             // Get the path to the folder
  307.             result = GetDirPathName (vRefNum, dirID, pathName);
  308.             if (result == noErr)
  309.             {
  310.                 // Delete it
  311.                 result = DeleteDirectory (vRefNum, dirID, (StringPtr)pathName);
  312.                 FailMessage (result != noErr, DeletePreferencesFolder: DeleteDirectory failed.);
  313.             }
  314.         }
  315.     }
  316.     else    // Bad parameter
  317.     {
  318.         result = paramErr;
  319.         DebugMessage (DeletePreferencesFolder: Bad parameter.);
  320.     }
  321.     return (result);
  322. }
  323.  
  324. //-----------------------------------------------------------------------
  325.  
  326. pascal Boolean
  327. PreferencesFileExists (OSType creator, OSType fileType)
  328. {
  329.     FSSpec    prefsFSSpec;
  330.     OSErr    result = noErr;
  331.     
  332.     // If file doesn't exist, fnfErr will be returned
  333.     result = GetPreferencesFileFSSpec (creator, fileType, &prefsFSSpec);
  334.     
  335.     return (result == noErr);
  336. }
  337.  
  338. //-----------------------------------------------------------------------
  339.  
  340. pascal OSErr
  341. GetPreferencesFileVersion (short fRefNum, short versID, 
  342.     NumVersion *numVersion, short *regionCode, 
  343.     ConstStr255Param shortVersionStr, ConstStr255Param longVersionStr)
  344. {
  345.     OSErr    result = noErr;
  346.     
  347.     // Make sure parameters are valid
  348.     if ((fRefNum != -1) && ((versID == kVers1) || (versID == kVers2)) && 
  349.         (numVersion != nil) && (regionCode != nil))
  350.     {
  351.         VersRecHndl    versHdl;
  352.         short        resID = versID;
  353.             
  354.         // Read the version resource
  355.         result = ReadPreference (fRefNum, 'vers', &resID, (Handle *)&versHdl);
  356.         if ((result == noErr) && (versHdl != nil))
  357.         {
  358.             *numVersion = (**versHdl).numericVersion;
  359.             *regionCode = (**versHdl).countryCode;
  360.             
  361.             // Note that the long version string is packed at the end of the
  362.             // short version string - this is the format for the 'vers'
  363.             // resource
  364.             BlockMoveData ((Ptr)((**versHdl).shortVersion), (Ptr)shortVersionStr,
  365.                 (**versHdl).shortVersion[0] + 1);
  366.             BlockMoveData ((Ptr)&((**versHdl).shortVersion[shortVersionStr[0] + 1]),
  367.                 (Ptr)longVersionStr, (**versHdl).shortVersion[shortVersionStr[0] + 1] + 1);
  368.                 
  369.             // Clean up
  370.             DisposeHandle ((Handle) versHdl);
  371.             result = MemError();
  372.             FailMessage (result != noErr, GetPreferencesFileVersion: DisposeHandle failed.);
  373.         }
  374.     }
  375.     else    // Bad parameter
  376.     {
  377.         result = paramErr;
  378.         DebugMessage (GetPreferencesFileVersion: Bad parameter.);
  379.     }
  380.     return (result);
  381. }
  382.  
  383. //-----------------------------------------------------------------------
  384.  
  385. pascal OSErr
  386. SetPreferencesFileVersion (short fRefNum, short versID, 
  387.     NumVersion *numVersion, short regionCode, 
  388.     ConstStr255Param shortVersionStr, ConstStr255Param longVersionStr)
  389. {
  390.     OSErr    result = noErr;
  391.     
  392.     // Make sure parameters are valid
  393.     if ((fRefNum != -1) && ((versID == kVers1) || (versID == kVers2)) && 
  394.         (numVersion != nil))
  395.     {
  396.         VersRecHndl    versHdl = (VersRecHndl) NewHandleClear (sizeof (VersRec));
  397.         
  398.         if (versHdl != nil)
  399.         {
  400.             short    resID = versID;
  401.             
  402.             (**versHdl).numericVersion = *numVersion;
  403.             (**versHdl).countryCode = regionCode;
  404.             
  405.             // Note that the long version string is packed at the end of the
  406.             // short version string - this is the format for the 'vers'
  407.             // resource
  408.             BlockMoveData ((Ptr)(shortVersionStr), (Ptr)((**versHdl).shortVersion),
  409.                 shortVersionStr[0] + 1);
  410.             BlockMoveData ((Ptr)(longVersionStr), 
  411.                 (Ptr)&((**versHdl).shortVersion[shortVersionStr[0] + 1]), 
  412.                 longVersionStr[0] + 1);
  413.                 
  414.             // Write the version resource
  415.             result = WritePreference (fRefNum, 'vers', &resID, (Handle) versHdl);
  416.         }
  417.         else    // Couldn't get any memory
  418.         {
  419.             result = MemError();
  420.             DebugMessage (SetPreferencesFileVersion: NewHandleClear failed.);
  421.         }
  422.     }
  423.     else    // Bad parameter
  424.     {
  425.         result = paramErr;
  426.         DebugMessage (SetPreferencesFileVersion: Bad parameter.);
  427.     }
  428.     return (result);
  429. }
  430.  
  431. //-----------------------------------------------------------------------
  432.  
  433. pascal OSErr
  434. ReadPreference (short fRefNum, ResType resourceType, short *resourceID, 
  435.     Handle *preference)
  436. {
  437.     OSErr    result = noErr;
  438.     
  439.     // Make sure parameters are valid
  440.     if ((fRefNum != -1) && (preference != nil))
  441.     {
  442.         short    savedResFile = CurResFile();    // Save off current resource file
  443.     
  444.         // Use this file
  445.         UseResFile (fRefNum);
  446.         result = ResError();
  447.         if (result == noErr)
  448.         {
  449.             // See if the resource is around
  450.             if ((resourceID != nil) && (*resourceID != 0))
  451.             {
  452.                 // Get the resource with the specified ID
  453.                 *preference = Get1Resource (resourceType, *resourceID);
  454.             }
  455.             else
  456.             {
  457.                 // Get the first resource of this type
  458.                 *preference = Get1IndResource (resourceType, 1);
  459.                 if ((*preference != nil) && (resourceID != nil))
  460.                 {
  461.                     Str255    dummy1;
  462.                     ResType    dummy2;
  463.                     
  464.                     // Get the resource ID
  465.                     GetResInfo (*preference, resourceID, &dummy2, dummy1);
  466.                 }
  467.             }
  468.  
  469.             // Did we get a resource successfully?
  470.             if (((result = ResError()) == noErr) && (*preference != nil))
  471.             {
  472.                 // Detach it
  473.                 DetachResource (*preference);
  474.                 result = ResError();
  475.                 FailMessage (result != noErr, ReadPreference: DetachResource failed.);
  476.             }
  477.             else    // Get1Resource failed
  478.             {    
  479.                 result = resNotFound;
  480.                 DebugMessage (ReadPreference: Get1Resource failed.);
  481.             }
  482.             
  483.             // Restore the resource file 
  484.             UseResFile (savedResFile);
  485.             result = ResError();
  486.             FailMessage (result != noErr, ReadPreference: UseResFile failed.);
  487.         }
  488.         else    // UseResFile failed
  489.         {
  490.             DebugMessage (ReadPreference: UseResFile failed.);
  491.         }
  492.     }
  493.     else    // Bad parameter
  494.     {
  495.         result = paramErr;
  496.         DebugMessage (ReadPreference: Bad parameter.);
  497.     }
  498.     return (result);
  499. }
  500.  
  501. //-----------------------------------------------------------------------
  502.  
  503. pascal OSErr
  504. WritePreference (short fRefNum, ResType resourceType, short *resourceID, 
  505.     Handle preference)
  506. {
  507.     OSErr    result = noErr;
  508.     
  509.     // Make sure parameters are valid
  510.     if ((fRefNum != -1) && (preference != nil))
  511.     {
  512.         Handle    localPref = preference;
  513.         
  514.         // Make a local copy of this preference
  515.         result = HandToHand (&localPref);
  516.         
  517.         if (result == noErr)
  518.         {
  519.             Handle    oldPref = nil;
  520.             Size    prefSize = GetHandleSize (localPref);    // Get size of preference to be added
  521.             Size    existingPrefSize = prefSize;
  522.             long    freeSpaceOnDisk;
  523.             short    vRefNum = FindVRefNum (fRefNum);
  524.             short    savedResFile = CurResFile();            // Save off current resource file
  525.             short    resID;
  526.             
  527.             // Get free disk space
  528.             freeSpaceOnDisk = GetVolFreeSpace (vRefNum);
  529.             
  530.             // Use this file
  531.             UseResFile (fRefNum);
  532.             result = ResError();
  533.             if (result == noErr)
  534.             {
  535.                 // See if this resource is already around
  536.                 if ((resourceID != nil) && (*resourceID != 0))
  537.                 {
  538.                     // Get the resource with the specified ID
  539.                     oldPref = Get1Resource (resourceType, *resourceID);
  540.                 }
  541.     
  542.                 // Did we find an existing resource?
  543.                 if (oldPref != nil)
  544.                 {
  545.                     // How big is it?
  546.                     existingPrefSize = GetHandleSize (oldPref);
  547.                     
  548.                     // Make sure that there's enough disk space available to
  549.                     // accomodate the resource that's replacing the old one -
  550.                     // if there's not, leave the old one in place, and return an error
  551.                     // We'll leave at least one allocation block left for the system
  552.                     if ((prefSize > existingPrefSize) && 
  553.                         (prefSize + GetVAllocationBlockSize (FindVRefNum (fRefNum)) > freeSpaceOnDisk))
  554.                     {
  555.                         result = dskFulErr;
  556.                         DebugMessage (WritePreference: Not enough disk space to write resource.);
  557.                     }
  558.                     else
  559.                     {
  560.                         // Get rid of it
  561.                         RmveResource (oldPref);
  562.                         if ((result = ResError()) == noErr)
  563.                         {
  564.                             // Update the file
  565.                             UpdateResFile (fRefNum);
  566.                             result = ResError();
  567.                             FailMessage (result != noErr, WritePreference: UpdateResFile failed.);
  568.                         }
  569.                         else    // RmveResource failed
  570.                         {
  571.                             DebugMessage (WritePreference: RmveResource failed.);
  572.                         }
  573.                         
  574.                         // Clean up
  575.                         DisposeHandle (oldPref);
  576.                         result = MemError();
  577.                         FailMessage (result != noErr, WritePreference: DisposeHandle failed.);
  578.                     }
  579.                 }
  580.                 
  581.                 if (result == noErr)
  582.                 {
  583.                     // Make sure there's room
  584.                     if (prefSize + GetVAllocationBlockSize (FindVRefNum (fRefNum)) > freeSpaceOnDisk)
  585.                     {
  586.                         result = dskFulErr;
  587.                         DebugMessage (WritePreference: Not enough disk space to write resource.);
  588.                     }
  589.                     else
  590.                     {
  591.                         // Figure out the resource ID to use
  592.                         if (resourceID != nil)
  593.                         {
  594.                             if (*resourceID == 0)
  595.                             {
  596.                                 // Get a unique resource ID
  597.                                 resID = Unique1ID (resourceType);
  598.                                 *resourceID = resID;
  599.                             }
  600.                             else
  601.                             {
  602.                                 resID = *resourceID;
  603.                             }
  604.                         }
  605.                         else
  606.                         {
  607.                             // Get a unique resource ID
  608.                             resID = Unique1ID (resourceType);
  609.                         }
  610.             
  611.                         // Add the resource
  612.                         AddResource (localPref, resourceType, resID, "\p");
  613.                         if ((result = ResError()) == noErr)
  614.                         {
  615.                             // Write it to the file
  616.                             WriteResource (localPref);
  617.                             FailMessage ((result = ResError()) != noErr, WritePreference: 
  618.                                 WriteResource failed.);
  619.                                 
  620.                             // Clean up
  621.                             ReleaseResource (localPref);
  622.                             FailMessage ((result = ResError()) != noErr, WritePreference: 
  623.                                 ReleaseResource failed.);
  624.                         }
  625.                         else    // AddResource failed
  626.                         {
  627.                             DebugMessage (WritePreference: AddResource failed.);
  628.                         }
  629.                     }
  630.                 }
  631.                 
  632.                 // Restore the resource file
  633.                 UseResFile (savedResFile);
  634.                 result = ResError();
  635.                 FailMessage (result != noErr, WritePreference: UseResFile failed.);
  636.             }
  637.             else    // UseResFile failed
  638.             {
  639.                 DebugMessage (WritePreference: UseResFile failed.);
  640.             }
  641.         }
  642.         else    // HandToHand failed
  643.         {
  644.             DebugMessage (WritePreference: HandToHand failed.);
  645.         }
  646.     }
  647.     else    // Bad parameter
  648.     {
  649.         result = paramErr;
  650.         DebugMessage (WritePreference: Bad parameter.);
  651.     }
  652.     return (result);
  653. }
  654.  
  655. //-----------------------------------------------------------------------
  656.  
  657. pascal OSErr
  658. DeletePreference (short fRefNum, ResType resourceType, short resourceID)
  659. {
  660.     OSErr    result = noErr;
  661.     
  662.     // Make sure parameters are valid
  663.     if (fRefNum != -1)
  664.     {
  665.         Handle    prefToKill;
  666.         short    savedResFile = CurResFile();    // Save off the current resource file
  667.         
  668.         // Use this file
  669.         UseResFile (fRefNum);
  670.         result = ResError();
  671.         if (result == noErr)
  672.         {
  673.             // Are there any of these resources around?
  674.             if (Count1Resources (resourceType) > 0)
  675.             {
  676.                 // See if this resource is around
  677.                 if (resourceID != 0)
  678.                 {
  679.                     // Get the resource with the specified ID
  680.                     prefToKill = Get1Resource (resourceType, resourceID);
  681.                 }
  682.                 else
  683.                 {
  684.                     // Get the first resource of this type
  685.                     prefToKill = Get1IndResource (resourceType, 1);
  686.                 }
  687.                 
  688.                 // Did we find a resource to delete?
  689.                 if (prefToKill != nil)
  690.                 {
  691.                     // Remove it
  692.                     RmveResource (prefToKill);
  693.                     if ((result = ResError()) == noErr)
  694.                     {
  695.                         // Update the file
  696.                         UpdateResFile (fRefNum);
  697.                         FailMessage ((result = ResError()) != noErr, DeletePreference: 
  698.                             UpdateResFile failed.);
  699.                     }
  700.                     else    // RmveResource failed
  701.                     {
  702.                         DebugMessage (DeletePreference: RmveResource failed.);
  703.                     }
  704.                     
  705.                     // Clean up
  706.                     DisposeHandle (prefToKill);
  707.                     result = MemError();
  708.                     FailMessage (result != noErr, DeletePreference: DisposeHandle failed.);
  709.                 }
  710.             }
  711.             else    // Couldn't find this resource
  712.             {
  713.                 result = resNotFound;
  714.                 DebugMessage (DeletePreference: Resource not found.);
  715.             }
  716.             
  717.             // Restore the resource file
  718.             UseResFile (savedResFile);
  719.             result = ResError();
  720.             FailMessage (result != noErr, DeletePreference: UseResFile failed.);
  721.         }
  722.         else    // UseResFile failed
  723.         {
  724.             DebugMessage (DeletePreference: UseResFile failed.);
  725.         }
  726.     }
  727.     else    // Bad parameter
  728.     {
  729.         result = paramErr;
  730.         DebugMessage (DeletePreference: Bad parameter.);
  731.     }
  732.     return (result);
  733. }
  734.  
  735. //-----------------------------------------------------------------------
  736.  
  737. static OSErr
  738. GetPrefsDirVRefNumAndDirID (ConstStr31Param folderName, 
  739.     Boolean createFolder, short *vRefNum, long *dirID)
  740. {
  741.     OSErr    result = noErr;
  742.     
  743.     // Make sure parameters are valid
  744.     if ((vRefNum != nil) && (dirID != nil))
  745.     {
  746.         long    id;
  747.         
  748.         // Locate the Preferences folder
  749.         result = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
  750.             vRefNum, &id);
  751.         if (result == fnfErr)
  752.         {
  753.             // No Preferences folder found, try to find the System Folder
  754.             result = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
  755.                 vRefNum, &id);
  756.             if (result != noErr)
  757.             {
  758.                 // Couldn't find the System Folder - we're hosed
  759.                 DebugMessage (GetPrefsDirVRefNumAndDirID: FindFolder failed.);
  760.                 goto BAIL;
  761.             }
  762.         }
  763.         else if (result != noErr)
  764.         { 
  765.             // Got some other kind of bad error from FindFolder when trying
  766.             // to find the Preferences folder
  767.             DebugMessage (GetPrefsDirVRefNumAndDirID: FindFolder failed.);
  768.             goto BAIL;
  769.         }
  770.         
  771.         // Are we using a custom preferences folder?
  772.         if (folderName != nil)
  773.         {
  774.             DirInfo    info;
  775.             
  776.             // See if the specified custom preferences folder is around
  777.             info.ioNamePtr = (StringPtr) folderName;
  778.             info.ioVRefNum = *vRefNum;
  779.             info.ioDrDirID = id;
  780.             info.ioFDirIndex = 0;
  781.             result = PBGetCatInfo ((CInfoPBPtr)&info, false);
  782.             if (result == noErr)
  783.             {
  784.                 *dirID = info.ioDrDirID;
  785.             }
  786.             else if ((result == fnfErr) && createFolder)
  787.             {
  788.                 // Try to create the specified custom preferences folder
  789.                 result = DirCreate (*vRefNum, id, folderName, dirID);
  790.                 FailMessage (result != noErr, GetPrefsDirVRefNumAndDirID: DirCreate failed.);
  791.             }
  792.             else    // PBGetCatInfo failed
  793.             {
  794.                 DebugMessage (GetPrefsDirVRefNumAndDirID: PBGetCatInfo failed.);
  795.             }
  796.         }
  797.         else    // Not using a custom preferences folder
  798.         {
  799.             *dirID = id;
  800.         }
  801.     }
  802.     else    // Bad parameter
  803.     {
  804.         result = paramErr;
  805.         DebugMessage (GetPrefsDirVRefNumAndDirID: Bad parameter.);
  806.     }
  807.     
  808. BAIL:
  809.     return (result);
  810. }
  811.  
  812. //-----------------------------------------------------------------------
  813.  
  814. static OSErr
  815. GetPreferencesFileFSSpec (OSType creator, OSType fileType,
  816.     FSSpec *file)
  817. {
  818.     OSErr    result = noErr;
  819.     
  820.     // Make sure parameters are valid
  821.     if (file != nil)
  822.     {
  823.         long    systemFolderDirID;
  824.         long    prefsFolderDirID;
  825.         short    vRefNum;
  826.         Boolean    hasPrefsDir;
  827.         Boolean    foundIt = false;
  828.         
  829.         // Find the Preferences folder dirID
  830.         result = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
  831.             &vRefNum, &prefsFolderDirID);
  832.         hasPrefsDir = (result == noErr);
  833.         
  834.         // Find the System Folder dirID
  835.         result = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
  836.             &vRefNum, &systemFolderDirID);
  837.             
  838.         // Did we find the System Folder OK?
  839.         if (result == noErr)
  840.         {
  841.             FSSpec    possibleMatch;
  842.             long    numMatches;
  843.             Boolean    firstSearch = true;
  844.             
  845.             // Check the Preferences folder first
  846.             if (hasPrefsDir)
  847.             {
  848.                 // Loop through the possible candidates until a candidate is found
  849.                 do
  850.                 {
  851.                     result = CreatorTypeFileSearch (nil, vRefNum, creator, fileType, 
  852.                         (FSSpecPtr) &possibleMatch, 1L, &numMatches, firstSearch);
  853.                         
  854.                     firstSearch = false;
  855.                     
  856.                     // Did we get a match?
  857.                     if (numMatches == 1)
  858.                     {
  859.                         // Check to see if this file is within the Preferences
  860.                         // folder or any of its nested folders
  861.                         if (DirIDInPrefsDir (vRefNum, possibleMatch.parID, prefsFolderDirID))
  862.                         {
  863.                             // Got one!
  864.                             foundIt = true;
  865.                             break;
  866.                         }
  867.                     }
  868.                 }
  869.                 while ((result == noErr) || (result == catChangedErr));
  870.             }
  871.             
  872.             // If we didn't find it in the Preferences folder, check the
  873.             // System Folder
  874.             if (!foundIt)
  875.             {
  876.                 // Loop through the possible candidates until a candidate is found
  877.                 firstSearch = true;
  878.                 do
  879.                 {
  880.                     result = CreatorTypeFileSearch (nil, vRefNum, creator, fileType, 
  881.                         (FSSpecPtr) &possibleMatch, 1L, &numMatches, firstSearch);
  882.                         
  883.                     firstSearch = false;
  884.                     
  885.                     // Did we get a match?
  886.                     if ((numMatches == 1) && (possibleMatch.parID == systemFolderDirID))
  887.                     {
  888.                         // Got one!
  889.                         foundIt = true;
  890.                         break;
  891.                     }
  892.                 }
  893.                 while ((result == noErr) || (result == catChangedErr));
  894.             }
  895.             
  896.             // If we found one, return it
  897.             if (foundIt)
  898.             {
  899.                 *file = possibleMatch;
  900.             }
  901.             else    // Didn't find a preferences file with the specified creator and file type
  902.             {
  903.                 result = fnfErr;
  904.                 DebugMessage (GetPreferencesFileFSSpec: Could not find preferences file.);
  905.             }
  906.         }
  907.         else    // Couldn't find the System Folder
  908.         {
  909.             DebugMessage (GetPreferencesFileFSSpec: FindFolder failed.);
  910.         }
  911.     }
  912.     else    // Bad parameter
  913.     {
  914.         result = paramErr;
  915.         DebugMessage (GetPreferencesFileFSSpec: Bad parameter.);
  916.     }
  917.     return (result);
  918. }
  919.  
  920. //-----------------------------------------------------------------------
  921.  
  922. static Boolean
  923. DirIDInPrefsDir (short vRefNum, long dirID, long prefsDirID)
  924. {
  925.     OSErr    result = noErr;
  926.     Boolean    inPrefsDir = false;
  927.     
  928.     // Make sure parameters are valid
  929.     if (vRefNum < 0)
  930.     {
  931.         // Is the dirID of the directory the same as the Preferences 
  932.         // folder dirID?
  933.         if (dirID == prefsDirID)
  934.         {
  935.             inPrefsDir = true;
  936.         }
  937.         else    // Nope, we need to follow the path up toward the root
  938.         {
  939.             DirInfo    info;
  940.             Str255    dirName;
  941.             Str255    pathName;
  942.             
  943.             // Initialize some stuff
  944.             
  945.             pathName[0] = '\0';
  946.         
  947.             info.ioDrParID = dirID;
  948.             info.ioNamePtr = dirName;
  949.             
  950.             // Walk the path upward, one directory at a time,
  951.             // until we either determine that the directory is
  952.             // in the Preferences folder, or until we hit the
  953.             // root directory (this always has a dirID of 2)
  954.             do
  955.             {
  956.                 info.ioVRefNum = vRefNum;
  957.                 info.ioFDirIndex = -1;
  958.                 info.ioDrDirID = info.ioDrParID;
  959.                 result = PBGetCatInfo ((CInfoPBPtr)&info, false);
  960.                 if (result == noErr)
  961.                 {
  962.                     // Is this the Preferences folder?
  963.                     if (info.ioDrParID == prefsDirID)
  964.                     {
  965.                         // Yep, we can leave now
  966.                         inPrefsDir = true;
  967.                         break;
  968.                     }
  969.                     else    // Nope, append this string to the path name and try again
  970.                     {
  971.                         result = CatenateStrings (dirName, "\p:", dirName);
  972.                         if (result == noErr)
  973.                         {
  974.                             result = CatenateStrings (dirName, pathName, pathName);
  975.                             if (result != noErr)
  976.                             {
  977.                                 // CatenateStrings failed
  978.                                 break;
  979.                             }
  980.                         }
  981.                         else    // CatenateStrings failed
  982.                         {
  983.                             break;
  984.                         }
  985.                     }
  986.                 }
  987.                 else    // PBGetCatInfo failed
  988.                 {
  989.                     DebugMessage (DirIDInPrefsDir: PBGetCatInfo failed.);
  990.                     break;
  991.                 }
  992.             }
  993.             while (info.ioDrDirID != 2);
  994.         }
  995.     }
  996.     else    // Bad parameter
  997.     {
  998.         DebugMessage (DirIDInPrefsDir: Bad parameter.);
  999.     }
  1000.     return (inPrefsDir);
  1001. }
  1002.  
  1003. //-----------------------------------------------------------------------
  1004.  
  1005. static short
  1006. FindVRefNum (short fRefNum)
  1007. {
  1008.     OSErr    result = noErr;
  1009.     short    vRefNum = 0;
  1010.     
  1011.     // Make sure parameters are valid
  1012.     if (fRefNum != -1)
  1013.     {
  1014.         FCBPBRec    fcbInfo;
  1015.         Str63        fName;
  1016.     
  1017.         // Set up parameter block
  1018.         fcbInfo.ioNamePtr = fName;
  1019.         fcbInfo.ioVRefNum = 0;
  1020.         fcbInfo.ioRefNum = fRefNum;
  1021.         fcbInfo.ioFCBIndx = 0;
  1022.         result = PBGetFCBInfoSync (&fcbInfo);
  1023.         if (result == noErr)
  1024.         {
  1025.             vRefNum = fcbInfo.ioFCBVRefNum;
  1026.         }
  1027.         else    // PBGetFCBInfoSync failed
  1028.         {
  1029.             DebugMessage (FindVRefNum: PBGetFCBInfoSync failed.);
  1030.         }
  1031.     }
  1032.     else    // Bad parameter
  1033.     {
  1034.         DebugMessage (FindVRefNum: Bad parameter.);
  1035.     }
  1036.     return (vRefNum);
  1037. }
  1038.  
  1039. //-----------------------------------------------------------------------
  1040.  
  1041. static unsigned long
  1042. GetVolFreeSpace (short vRefNum)
  1043. {
  1044.     HParamBlockRec    pb;
  1045.     OSErr            result = noErr;
  1046.  
  1047.     pb.volumeParam.ioNamePtr = nil;            // We don't care about the name
  1048.     pb.volumeParam.ioVRefNum = vRefNum;
  1049.     pb.volumeParam.ioVolIndex = 0;            // Use ioVRefNum only
  1050.     result = PBHGetVInfo (&pb, false);
  1051.  
  1052.     if (result == noErr)
  1053.     {
  1054.         // Calculate the free space in bytes
  1055.         return (pb.volumeParam.ioVFrBlk * pb.volumeParam.ioVAlBlkSiz);
  1056.     }
  1057.     else    // PBHGetVInfo failed
  1058.     {
  1059.         DebugMessage (GetVolFreeSpace: PBHGetVInfo failed.);
  1060.         return (0L);
  1061.     }
  1062. }
  1063.  
  1064. //-----------------------------------------------------------------------
  1065.  
  1066. static unsigned long
  1067. GetVAllocationBlockSize (short vRefNum)
  1068. {
  1069.     HParamBlockRec    pb;
  1070.     OSErr            result = noErr;
  1071.     
  1072.     pb.volumeParam.ioNamePtr = nil;        // We don't care about the name
  1073.     pb.volumeParam.ioVRefNum = vRefNum;    
  1074.     pb.volumeParam.ioVolIndex = 0;        // Use ioVRefNum only
  1075.     result = PBHGetVInfo (&pb, false);
  1076.     
  1077.     if (result == noErr)
  1078.     {
  1079.         return (pb.volumeParam.ioVAlBlkSiz);
  1080.     }
  1081.     else
  1082.     {
  1083.         return (0L);
  1084.     }
  1085. }
  1086.  
  1087. //-----------------------------------------------------------------------
  1088.  
  1089. static OSErr
  1090. GetDirPathName (short vRefNum, long dirID, Str255 pathName)
  1091. {
  1092.     OSErr    result = noErr;
  1093.     
  1094.     // Make sure parameters are valid
  1095.     if (vRefNum < 0)
  1096.     {
  1097.         DirInfo    info;
  1098.         Str255    dirName;
  1099.         
  1100.         // Initialize some stuff
  1101.         
  1102.         pathName[0] = '\0';
  1103.     
  1104.         info.ioDrParID = dirID;
  1105.         info.ioNamePtr = dirName;
  1106.         
  1107.         // Walk the path upward, one directory at a time,
  1108.         // until we hit the root directory (this always 
  1109.         // has a dirID of 2)
  1110.         do
  1111.         {
  1112.             info.ioVRefNum = vRefNum;
  1113.             info.ioFDirIndex = -1;
  1114.             info.ioDrDirID = info.ioDrParID;
  1115.             result = PBGetCatInfo ((CInfoPBPtr)&info, false);
  1116.             if (result == noErr)
  1117.             {
  1118.                 result = CatenateStrings (dirName, "\p:", dirName);
  1119.                 if (result == noErr)
  1120.                 {
  1121.                     result = CatenateStrings (dirName, pathName, pathName);
  1122.                     if (result != noErr)
  1123.                     {
  1124.                         // CatenateStrings failed
  1125.                         break;
  1126.                     }
  1127.                 }
  1128.                 else    // CatenateStrings failed
  1129.                 {
  1130.                     break;
  1131.                 }
  1132.             }
  1133.             else    // PBGetCatInfo failed
  1134.             {
  1135.                 DebugMessage (GetDirPathName: PBGetCatInfo failed.);
  1136.                 break;
  1137.             }
  1138.         }
  1139.         while (info.ioDrDirID != 2);
  1140.     }
  1141.     else    // Bad parameter
  1142.     {
  1143.         result = paramErr;
  1144.         DebugMessage (GetDirPathName: Bad parameter.);
  1145.     }
  1146.     return (result);
  1147. }
  1148.  
  1149. //-----------------------------------------------------------------------
  1150.  
  1151. static OSErr
  1152. CopyString (ConstStr255Param theSourceStr, Str255 theDestStr)
  1153. {
  1154.     OSErr    result = noErr;
  1155.  
  1156.     // Make sure parameters are valid
  1157.     if ((theSourceStr != nil) && (theDestStr != nil))
  1158.     {
  1159.         BlockMoveData ((Ptr)theSourceStr, (Ptr)theDestStr, theSourceStr[0] + 1);
  1160.     }
  1161.     else    // Bad parameter
  1162.     {
  1163.         result = paramErr;
  1164.         DebugMessage (StrCopy: Bad parameter.);
  1165.     }
  1166.     return (result);
  1167. }
  1168.  
  1169. //-----------------------------------------------------------------------
  1170.  
  1171. static OSErr
  1172. CatenateStrings (ConstStr255Param theFirstStr,
  1173.     ConstStr255Param theSecondStr, Str255 theCatenatedStr)
  1174. {
  1175.     OSErr    result = noErr;
  1176.     
  1177.     // Make sure parameters are valid
  1178.     if ((theFirstStr != nil) && (theSecondStr != nil) && 
  1179.         (theCatenatedStr != nil))
  1180.     {
  1181.         Str255    catenatedStr;
  1182.         Str255    secondStr;
  1183.         long    tempSize;
  1184.         short    combinedLength = theFirstStr[0] + theSecondStr[0];
  1185.         short    secondStrLength = theSecondStr[0];
  1186.         
  1187.         // Can both strings fit in a Str255?
  1188.         if (combinedLength > 255)
  1189.         {
  1190.             // Nope, let's shorten the second string to fit
  1191.             secondStrLength = 255 - theFirstStr[0];
  1192.         }
  1193.  
  1194.         // Copy the strings
  1195.         BlockMoveData ((Ptr)theFirstStr, (Ptr)catenatedStr, theFirstStr[0] + 1);
  1196.         BlockMoveData ((Ptr)theSecondStr, (Ptr)secondStr, secondStrLength + 1);
  1197.     
  1198.         // Copy the second string to the end of the first string
  1199.         tempSize = catenatedStr[0];
  1200.         catenatedStr[0] += secondStr[0];
  1201.         BlockMoveData ((Ptr)&secondStr[1], (Ptr)&catenatedStr[tempSize + 1], 
  1202.             secondStr[0]);
  1203.         
  1204.         // Copy the catenated string back out
  1205.         BlockMoveData ((Ptr)catenatedStr, (Ptr)theCatenatedStr, 
  1206.             catenatedStr[0] + 1);
  1207.     }
  1208.     else    // Bad parameter
  1209.     {
  1210.         result = paramErr;
  1211.         DebugMessage (StrCatenate: Bad parameter.);
  1212.     }
  1213.     return (result);
  1214. }
  1215.  
  1216. //-----------------------------------------------------------------------
  1217.  
  1218. static OSErr
  1219. CopyResource (ResType theType, short theID, FSSpec *fileToCopyTo)
  1220. {
  1221.     OSErr    result = noErr;
  1222.     
  1223.     // Make sure parameters are valid
  1224.     if (fileToCopyTo != nil)
  1225.     {
  1226.         Handle    resToBeCopied = GetResource (theType, theID);
  1227.         short    appResRefNum;
  1228.         
  1229.         if ((result = ResError()) == noErr)
  1230.         {
  1231.             // Get the application's resource refNum
  1232.             appResRefNum = LMGetCurApRefNum();
  1233.             if ((resToBeCopied != nil) &&
  1234.                 (appResRefNum == HomeResFile (resToBeCopied)))
  1235.             {
  1236.                 Handle    resToCopyTo;
  1237.                 short    resAttributes;
  1238.                 short    copyToFileResRefNum;
  1239.                 short    savedResFile = CurResFile();
  1240.                 
  1241.                 // Get the attributes of the resource to be copied
  1242.                 resAttributes = GetResAttrs (resToBeCopied);
  1243.                 
  1244.                 // Detach the resource to be coped
  1245.                 DetachResource (resToBeCopied);
  1246.                 if ((result = ResError()) == noErr)
  1247.                 {
  1248.                     // Open the file to copy to
  1249.                     copyToFileResRefNum = FSpOpenResFile (fileToCopyTo, fsRdWrPerm);
  1250.                     if ((result = ResError()) == noErr)
  1251.                     {
  1252.                         // Set the resource refNum
  1253.                         UseResFile (copyToFileResRefNum);
  1254.                         
  1255.                         // Check for existing resources with this type and ID in
  1256.                         // the file we're copying to, and remove any we find
  1257.                         do
  1258.                         {
  1259.                             // Get a resource
  1260.                             resToCopyTo = GetResource (theType, theID);
  1261.  
  1262.                             // Is the resource's res file the same as the
  1263.                             // file we're trying to copy to?
  1264.                             if (HomeResFile (resToCopyTo) == copyToFileResRefNum)
  1265.                             {
  1266.                                 // Remove it
  1267.                                 RmveResource (resToCopyTo);
  1268.                                 FailMessage ((result = ResError()) != noErr, CopyResource: RmveResource failed.);
  1269.                                 DisposeHandle (resToCopyTo);
  1270.                                 FailMessage ((result = MemError()) != noErr, CopyResource: DisposeHandle failed.);
  1271.                             }
  1272.                         }
  1273.                         while (HomeResFile (resToCopyTo) != copyToFileResRefNum);
  1274.                         
  1275.                         // Add the resource
  1276.                         AddResource (resToBeCopied, theType, theID, "\p");
  1277.                         if ((result = ResError()) == noErr)
  1278.                         {
  1279.                             // Set up the resource's attributes
  1280.                             SetResAttrs (resToBeCopied, resAttributes);
  1281.                             ChangedResource (resToBeCopied);
  1282.                             FailMessage ((result = ResError()) != noErr, CopyResource: ChangedResource failed.);
  1283.                         }
  1284.                         
  1285.                         // Close the file
  1286.                         CloseResFile (copyToFileResRefNum);
  1287.                         
  1288.                         // Restore resource file
  1289.                         UseResFile (savedResFile);
  1290.                     }
  1291.                     else    // FSpOpenResFile failed
  1292.                     {
  1293.                         DebugMessage (CopyResource: FSpOpenResFile failed.);
  1294.                     }
  1295.                 }
  1296.                 else    // DetachResource failed
  1297.                 {
  1298.                     DebugMessage (CopyResource: DetachResource failed.);
  1299.                 }
  1300.             }
  1301.         }
  1302.         else    // GetResource failed
  1303.         {
  1304.             DebugMessage (CopyResource: GetResource failed.);
  1305.         }
  1306.     }
  1307.     else    // Bad parameter
  1308.     {
  1309.         result = paramErr;
  1310.         DebugMessage (CopyResource: Bad parameter.);
  1311.     }
  1312.     return (result);
  1313. }
  1314.  
  1315. //-----------------------------------------------------------------------
  1316.  
  1317.  
  1318.  
  1319.